/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/


const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECT = 'reject';
/**
 * x 可能为promise或者其他值
*/
const resolvePromise = (promiseObj,x, resolve, reject)=>{
    if(promiseObj === x ){
        return reject(new TypeError('promise被循环调用了'))
    }
    if (x instanceof MyPromise) {
        // promise
        x.then(resolve,reject)
    }else{
        // 普通值
        resolve(x)
    }
}

class MyPromise {
    constructor (executor){
        try {
            executor(this.resolve,this.reject)
        } catch (error) {
            this.reject(error)
        }
    }
    // 状态
    status = PENDING
    // 值
    value = undefined
    // 错误
    error = undefined
    // 成功回调，因为可以写多个promise.then，这里声明的是数组
    successCB = []
    // 失败回调，同上
    failCB = []
    
    resolve = val =>{
        if(this.status !== PENDING) return
        // console.log('resolve');
        this.status = FULFILLED
        this.value = val
        if (this.successCB.length) {
            this.successCB.shift()()
        }

    }

    reject = err =>{
        if(this.status !== PENDING) return
        // console.log('reject');
        this.status = REJECT
        this.error = err
        if (this.failCB.length) {
            this.failCB.shift()()
        }
    }

    then = (successCB,failCB) =>{
        // console.log('then');
        // 实现then().then(v=>{})这样的无参then给下一个then传递上面的数据
        successCB = successCB || (value => value)
        failCB = failCB || (err => {throw err})

        let p = new MyPromise((res,rej)=>{

            // 异步情况
            if(this.status === PENDING){
                this.successCB.push(()=>{
                    setTimeout(() => {//因为 p 在使用时未能获取，所以这部分代码需要异步
                        try {
                            let x = successCB(this.value)
                            // 判断 x 的值是普通值还是promise对象
                            // 如果是普通值，直接调用resolve
                            // 如果是promise对象，查看对象结果
                            // 再根据结果决定嗲用resolve还是reject
                            resolvePromise(p,x,res,rej)
                        } catch (error) {
                            rej(error)
                        }
                        
                    }, 0);
                })
                this.failCB.push(()=>{
                    setTimeout(() => {//因为 p 在使用时未能获取，所以这部分代码需要异步
                        try {
                            let x = failCB(this.error)
                            // 判断 x 的值是普通值还是promise对象
                            // 如果是普通值，直接调用resolve
                            // 如果是promise对象，查看对象结果
                            // 再根据结果决定嗲用resolve还是reject
                            resolvePromise(p,x,res,rej)
                        } catch (error) {
                            rej(error)
                        }
                        
                    }, 0);
                })

            // 同步resolve情况
            }else if(this.status === FULFILLED){
                setTimeout(() => {//因为 p 在使用时未能获取，所以这部分代码需要异步
                    try {
                        let x = successCB(this.value)
                        // 判断 x 的值是普通值还是promise对象
                        // 如果是普通值，直接调用resolve
                        // 如果是promise对象，查看对象结果
                        // 再根据结果决定嗲用resolve还是reject
                        resolvePromise(p,x,res,rej)
                    } catch (error) {
                        rej(error)
                    }
                    
                }, 0);
            
            // 同步reject情况
            }else if(this.status === REJECT){
                setTimeout(() => {//因为 p 在使用时未能获取，所以这部分代码需要异步
                    try {
                        let x = failCB(this.error)
                        // 判断 x 的值是普通值还是promise对象
                        // 如果是普通值，直接调用resolve
                        // 如果是promise对象，查看对象结果
                        // 再根据结果决定嗲用resolve还是reject
                        resolvePromise(p,x,res,rej)
                    } catch (error) {
                        rej(error)
                    }
                    
                }, 0);
            }

        })

        return p
        
    }
    
    finally = (cb)=>{
        return this.then(val=>{
            return MyPromise.resolve(cb()).then(()=>val)
        },e=>{
            return MyPromise.resolve(cb()).then(()=>{throw e})
            
        })
    }

    catch =(failCB)=> {
        return this.then(undefined, failCB)
    }

    // 使用new MyPromise的时候不可使用，所以要用static
    static all(array){
        // 用于保存promise数组的结果
        let result = []
        // 用于判断是否完成promise
        let idx = 0

        return new MyPromise((res,rej)=>{
            function addData(key,val) {
                result[key] = val
                idx++
                if (idx >= array.length) {
                    res(result)
                }
            }
            for (let i = 0; i < array.length; i++) {
                const item = array[i];
                if(item instanceof MyPromise){
                    // promise对象
                    item.then(val=>{addData(i, val)},rej)
                }else{
                    // 普通值
                    addData(i, item)
                }
            }
        })
    }

    static resolve(val){
        if(val instanceof MyPromise){
            return val
        }else{
            return new MyPromise(res=>res(val))
        }
    }
}